package com.niezhiliang.springboot.rabbitmq.common.util;

import java.util.Random;

/**
 * 提供10进制数与32进制，10进制数与64进制的相互转换。这种转换主要的作用是压缩数据。
 * @author sffzh
 */
public class CompressEncoding
{
    final static char[] digits64 = {  
        '0' , '1' , '2' , '3' , '4' , '5' ,  
        '6' , '7' , '8' , '9' , 
        'A' , 'B' , 'C' , 'D' , 'E' , 'F' ,  
        'G' , 'H' , 'I' , 'J' , 'K' , 'L' ,  
        'M' , 'N' , 'O' , 'P' , 'Q' , 'R' ,  
        'S' , 'T' , 'U' , 'V' , 'W' , 'X' ,  
        'Y' , 'Z' ,
        'a' , 'b' ,  
        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,  
        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,  
        'o' , 'p' , 'q' , 'r' , 's' , 't' ,  
        'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,  
        '-' , '_'  ,  
        },
        digits32={//32进制采用了10个数字和22个大写字母，大写字母中IOUZ四个字母未采用
    	'0' , '1' , '2' , '3' , '4' , '5' ,  
        '6' , '7' , '8' , '9' , 
        'A' , 'B' , 'C' , 'D' , 'E' , 'F' ,  
        'G' , 'H' , 	 'J' , 'K' , 'L' ,  //I-18,73
        'M' , 'N' , 	 'P' , 'Q' , 'R' ,  //O-79
        'S' , 'T' ,		 'V' , 'W' , 'X' ,  //U-85
        'Y'  }; //Z-90
    //笔记：18位数转成64进制后长度一定为10位，转成32进制后长度一定为12位。
    /** 
     * @param args 
     */  
    public static void main(String[] args) {//TODO 
        System.err.println(CompressNumber(999999999999999999L, Radix.B64));
        System.err.println(CompressNumber(888888888888888888L, Radix.B64));
        System.err.println(CompressNumber(5685465L, Radix.B64));
        String r=CompressNumber("1999999999998888888888888888885685465", Radix.B32);
        System.err.println(r);
        System.err.println("1999999999998888888888888888885685465".length());
        System.err.println(uncompressNumberStr(CompressNumber("9999999999999999998888888888888888885685465", Radix.B32), Radix.B32));
        System.err.println(uncompressNumberStr(CompressNumber("9999999999999999998888888888888888885685465", Radix.B32), Radix.B32).equals("9999999999999999998888888888888888885685465"));
    }
    
    public static String random32Char(int randomLength) {
    	
    	char[] result = new char[randomLength];
    	Random r = new Random();
    	for(int i = 0 ;i<randomLength;i++){
    		result[i] = digits32[r.nextInt(32)];
    	}
    	return new String(result);
    }
    
    /**
     * 进制选择，64进制或32进制
     * @author sffzh
     *
     */
    public enum  Radix{
    	B64,B32
    }
    
    
    
    /** 
     * 把10进制的数字转换成64进制 
     * @param number 
     * @param r 进制32或64
     * @return 
     */  
    public static String CompressNumber(long number, Radix r) {
        char[] buf = new char[64];
        char[] digits;
        int charPos = 64;
        int shift;
        if(r== Radix.B32){
        	shift=5;
        	digits=CompressEncoding.digits32;
        }else{
        	shift=6;
        	digits=CompressEncoding.digits64;
        }
        long radix = 1 << shift;  
        long mask = radix - 1;  
        do {  
            buf[--charPos] = digits[(int)(number & mask)];  
            number >>>= shift;  
        } while (number != 0);  
        return new String(buf, charPos, (64 - charPos));  
       }  
    
    
    /** 
     * 把10进制的任意长度的数字转换成64进制 或 32进制
     * @param number 
     * @param r 进制，32进制或64进制
     * @return 
     */  
    public static String CompressNumber(String number, Radix r) {
    	int i=0;
    	long pit;
    	StringBuilder sb=new StringBuilder();
    	while(i+18<number.length()){
    		
    		pit=Long.parseLong(number.substring(i,i+=18));
    		sb.append(CompressNumber(pit, r));
    	}
		pit=Long.parseLong(number.substring(i));
		sb.append(CompressNumber(pit, r));
    	
    	return sb.toString();
    }

    /** 
     * 把64进制或32进制的字符串转换成10进制的字符串
     * @param decompStr 
     * @return 
     */  
    public static String uncompressNumberStr(String decompStr, Radix r)  
    {
    	int i=0;
    	int shift=r== Radix.B32?12:10;
    	StringBuilder sb=new StringBuilder();
    	while(i+shift<decompStr.length()){
    		sb.append(UncompressNumber(decompStr.substring(i,i+=shift), r));
    	}
		sb.append(UncompressNumber(decompStr.substring(i), r));
    	return sb.toString();
    }

    
    /** 
     * 把64进制或32进制的字符串转换成10进制 
     * @param decompStr 
     * @return 
     */  
    public static long UncompressNumber(String decompStr, Radix r)  
    {
    	if(decompStr.length()>13)return -1;
    	int shift;
        if(r== Radix.B32){
        	shift=5;
        }else{
        	shift=6;
        }
        long result=0;  
        for (int i =  decompStr.length()-1; i >=0; i--) {  
            if(i==decompStr.length()-1)  
            {  
                result+=getCharIndexNum(decompStr.charAt(i),r);  
            }else
            	result+=(getCharIndexNum(decompStr.charAt(i),r))<<(shift*(decompStr.length()-1-i));  
            	
        }  
        return result;  
    }     
    /** 
     *  
     * @param ch 
     * @param r 
     * @return 
     */  
    private static long getCharIndexNum(char ch, Radix r)  
    {  
        int num=((int)ch);  
        if(num>=48&&num<=57)  
        {  
            return num-48;  
        }else if(r== Radix.B32){
        	if(num<=72){//A-H,I=73
        		return num-55;
        	}else if(num<=78){//O=79
        		return num-56;
        	}else if(num<=84){//U=85
        		return num-57;
        	}else{
        		return num-58;
        	}
        }
        else if(num>=65&&num<=90)  //10-35
        {  
            return num-55;  
        }else if(num>=97&&num<=122)  //36-61
        {  
            return num-61;  
        }else if(num==45)  
        {  
            return 62;  
        }  
        else if (num == 95)  
        {  
            return 63;  
        }  
        return 0;  
    }  
  
}  